home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 3 / Amiga Tools 3.iso / grafik / raytracing / rayshade-4.0.6.3 / libray / libobj / geom.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-09  |  9.4 KB  |  451 lines

  1. /*
  2.  * object.c
  3.  *
  4.  * Copyright (C) 1989, 1991, Craig E. Kolb
  5.  * All rights reserved.
  6.  *
  7.  * This software may be freely copied, modified, and redistributed
  8.  * provided that this copyright notice is preserved on all copies.
  9.  *
  10.  * You may not distribute this software, in whole or in part, as part of
  11.  * any commercial product without the express consent of the authors.
  12.  *
  13.  * There is no warranty or other guarantee of fitness of this software
  14.  * for any purpose.  It is provided solely "as is".
  15.  *
  16.  * geom.c,v 4.1 1994/08/09 07:58:59 explorer Exp
  17.  *
  18.  * geom.c,v
  19.  * Revision 4.1  1994/08/09  07:58:59  explorer
  20.  * Bump version to 4.1
  21.  *
  22.  * Revision 1.1.1.1  1994/08/08  04:52:09  explorer
  23.  * Initial import.  This is a prerelease of 4.0.6enh3, or 4.1 possibly.
  24.  *
  25.  * Revision 4.0.1.1  91/09/29  15:43:15  cek
  26.  * patch1: GeomBounds now inflates bounds by EPSILON.
  27.  * 
  28.  * Revision 4.0  91/07/17  14:37:47  kolb
  29.  * Initial version.
  30.  * 
  31.  */
  32. #include "geom.h"
  33. #include "list.h"
  34. #include "libcommon/sampling.h"
  35.  
  36. static void GeomBounds(), GeomBoundsAnimated();
  37. void GeomResolveAssoc();    /* probably static */
  38.  
  39. Geom *
  40. GeomCreate(objptr, methods)
  41. GeomRef objptr;
  42. Methods *methods;
  43. {
  44.     Geom *obj;
  45.  
  46.     if (objptr == (GeomRef)NULL)
  47.         return (Geom *)NULL;
  48.         
  49.     obj = (Geom *)share_calloc(1, sizeof(Geom));
  50.     obj->obj = objptr;
  51.     obj->methods = methods;
  52.     obj->animtrans = FALSE;
  53.     obj->trans = obj->transtail = (Trans *) NULL;
  54.     obj->frame = -1;    /* impossible value */
  55.     BoundsInit(obj->bounds);
  56. #ifdef SHAREDMEM
  57.     /*
  58.      * If the counter is in shared memory, processes will
  59.      * be modifying it left-and-right.  So, we cheat and
  60.      * make counter a pointer to a non-shared location and
  61.      * store the value there.
  62.      */
  63.     new->counter = (unsigned long *)Malloc(sizeof(unsigned long));
  64.     *new->counter = 0;
  65. #endif
  66.     return obj;
  67. }
  68.  
  69. /*
  70.  * Return a copy of the given object.
  71.  * Note that surface, texturing, and transformation information
  72.  * is copied by reference.
  73.  */
  74. Geom *
  75. GeomCopy(obj)
  76. Geom *obj;
  77. {
  78.     Geom *new;
  79.  
  80.     new = GeomCreate(obj->obj, obj->methods);
  81.     /* Share texturing, name, #prims, surface info */
  82.     new->name = obj->name;
  83.     new->texture = obj->texture;
  84.     new->surf = obj->surf;
  85.     new->prims = obj->prims;
  86.     new->trans = obj->trans;
  87.     new->animtrans = obj->animtrans;
  88.     new->transtail = obj->transtail;
  89.     /* copy bounds */
  90.     BoundsCopy(obj->bounds, new->bounds);
  91.     return new;
  92. }
  93.  
  94. /*
  95.  * Report bounding box and number of primitives in object.
  96.  */
  97. void
  98. AggregatePrintInfo(obj, fp)
  99. Geom *obj;
  100. FILE *fp;
  101. {
  102.     if (fp) {
  103.         if (obj->name && obj->name[0])
  104.             fprintf(fp,"%s \"%s\":\n", GeomName(obj), obj->name);
  105.         else
  106.             fprintf(fp,"%s:\n", GeomName(obj));
  107.         if (!UNBOUNDED(obj))
  108.             BoundsPrint(obj->bounds, fp);
  109.         fprintf(fp,"\t%lu primitive%c\n",obj->prims,
  110.             obj->prims == 1 ? ' ' : 's');
  111.     }
  112. }
  113.  
  114. /*
  115.  * Convert the given object from a linked list of objects to
  116.  * the desired aggregate type.
  117.  */
  118. int
  119. AggregateConvert(obj, objlist)
  120. Geom *obj, *objlist;
  121. {
  122.     if (!IsAggregate(obj)) {
  123.         RLerror(RL_ABORT, "A %s isn't an aggregate.\n",
  124.             GeomName(obj));
  125.         return 0;
  126.     }
  127.  
  128.     return (*obj->methods->convert)(obj->obj, objlist);
  129. }
  130.  
  131. /*
  132.  * This should really be called
  133.  * GeomInitialize
  134.  * or something.
  135.  */
  136. void
  137. GeomComputeBounds(obj)
  138. Geom *obj;
  139. {
  140.     if (obj->frame == Sampling.framenum)
  141.         return;
  142.  
  143.     if (!obj->animtrans) {
  144.         /*
  145.          * If it isn't animated,
  146.          * just compute bbox directly 
  147.          */
  148.         GeomBounds(obj, obj->bounds);
  149.     } else {
  150.         /*
  151.          * Animated things are gonna get a bbox
  152.          * which is large enough to enclose all
  153.          * the places where the object goes.
  154.          */
  155.         GeomBoundsAnimated(obj);
  156.     }
  157.     /*
  158.      * Enlarge by EPSILON in each direction just to
  159.      * be on the safe side.
  160.      */
  161.     obj->bounds[LOW][X] -= EPSILON;
  162.     obj->bounds[HIGH][X] += EPSILON;
  163.     obj->bounds[LOW][Y] -= EPSILON;
  164.     obj->bounds[HIGH][Y] += EPSILON;
  165.     obj->bounds[LOW][Z] -= EPSILON;
  166.     obj->bounds[HIGH][Z] += EPSILON;
  167.     /*
  168.      * Mark the fact that that the obj is initialized
  169.      * for this frame.
  170.      */
  171.     obj->frame = Sampling.framenum;
  172.     obj->counter = 0;
  173. }
  174.  
  175. static void
  176. GeomBoundsAnimated(obj)
  177. Geom *obj;
  178. {
  179.     int i, m;
  180.     Float newbounds[2][3];
  181.     Float window, subwindow, jitter, subjitter;
  182.  
  183.     /*
  184.      * For each possible screen sample,
  185.      * choose TIME_SUB_SAMPLES times and recompute the
  186.      * bounds of obj at that time,
  187.      * expanding the computed bounding box appropriately.
  188.      */
  189.     BoundsInit(obj->bounds);
  190.     jitter = Sampling.shutter / Sampling.totsamples;
  191.     subjitter = jitter / (Float)TIME_SUB_SAMPLES;
  192.     window = Sampling.starttime;
  193.     for (i = 0; i < Sampling.totsamples; i++, window += jitter) {
  194.         subwindow = window;
  195.         for (m = 0; m < TIME_SUB_SAMPLES; m++, subwindow += subjitter) {
  196.             /*
  197.              * Set the current time.
  198.              */
  199.             TimeSet(subwindow + subjitter*nrand());
  200.             /*
  201.              * Resolve the objects geometric associations
  202.              */
  203.             GeomResolveAssoc(obj);
  204.             /*
  205.              * Compute bounds and expand current bounds.
  206.              */
  207.             GeomBounds(obj, newbounds);
  208.             BoundsEnlarge(obj->bounds, newbounds);
  209.         }
  210.     }
  211.     /*
  212.      * Also sample at time extremes, as for many
  213.      * movements, extremes occur at beginning/end times.
  214.      */
  215.     TimeSet(Sampling.starttime);
  216.     GeomResolveAssoc(obj);
  217.     GeomBounds(obj, newbounds);
  218.     BoundsEnlarge(obj->bounds, newbounds);
  219.  
  220.     TimeSet(Sampling.starttime + Sampling.shutter);
  221.     GeomResolveAssoc(obj);
  222.     GeomBounds(obj, newbounds);
  223.     BoundsEnlarge(obj->bounds, newbounds);
  224. }
  225.  
  226. void
  227. GeomResolveAssoc(obj)
  228. Geom *obj;
  229. {
  230.     /*
  231.      * PrimResolveAssoc(obj);
  232.      */
  233.     TransResolveAssoc(obj->trans);
  234. }
  235.  
  236. /*
  237.  * Set "bounds" of object to be the extent of the primitive.
  238.  */
  239. static void
  240. GeomBounds(obj, bounds)
  241. Geom *obj;
  242. Float bounds[2][3];
  243. {
  244.     Trans *trans;
  245.  
  246.     if (!obj || !obj->methods->bounds)
  247.         RLerror(RL_ABORT, "Can't compute bounds of \"%s\".\n",
  248.             GeomName(obj));
  249.     (*obj->methods->bounds) (obj->obj, bounds);
  250.     bounds[LOW][X] -= EPSILON;
  251.     bounds[LOW][Y] -= EPSILON;
  252.     bounds[LOW][Z] -= EPSILON;
  253.     bounds[HIGH][X] += EPSILON;
  254.     bounds[HIGH][Y] += EPSILON;
  255.     bounds[HIGH][Z] += EPSILON;
  256.     if (obj->trans) {
  257.         for (trans = obj->trans; trans; trans = trans->next)
  258.             BoundsTransform(&trans->trans, bounds);
  259.     }
  260. }
  261.  
  262. char *
  263. GeomName(obj)
  264. Geom *obj;
  265. {
  266.     if (obj->methods->name)
  267.         return (*obj->methods->name)();
  268.  
  269.     return "unknown";
  270. }
  271.  
  272. void
  273. GeomStats(obj, tests, hits)
  274. Geom *obj;
  275. unsigned long *tests, *hits;
  276. {
  277.     if (obj && obj->methods->stats)
  278.         (*obj->methods->stats)(tests, hits);
  279.     else {
  280.         *tests = *hits = 0;
  281.     }
  282. }
  283.  
  284. /*
  285.  * Push an object onto the head of the given stack, returning
  286.  * the new head.
  287.  */
  288. GeomList *
  289. GeomStackPush(obj, list)
  290. Geom *obj;
  291. GeomList *list;
  292. {
  293.     GeomList *new;
  294.     /*
  295.      * Pretty simple.
  296.      * Make new element point to old head and return new head.
  297.      */
  298.     new = (GeomList *)Malloc(sizeof(GeomList));
  299.     new->obj = obj;
  300.     new->next = list;
  301.     return new;
  302. }
  303.  
  304. /*
  305.  * Pop the topmost object off of the given stack, returning the new head.
  306.  * The old head is freed, but the object it points to is not.
  307.  */
  308. GeomList *
  309. GeomStackPop(list)
  310. GeomList *list;
  311. {
  312.     GeomList *ltmp;
  313.  
  314.     ltmp = list->next;    /* Save new head. */
  315.     free((voidstar)list);    /* Free old head. */
  316.     return ltmp;        /* Return new head. */
  317. }
  318.  
  319. Methods *
  320. MethodsCreate()
  321. {
  322.     return (Methods *)share_calloc(1, sizeof(Methods));
  323. }
  324.  
  325. /*
  326.  * Call appropriate routine to compute UV and, if non-null,
  327.  * dpdu and dpdv at given point on the given primitive.  The
  328.  * normal is used to facilitate computation of u, v, and the
  329.  * partial derivatives.
  330.  */
  331. void
  332. PrimUV(prim, pos, norm, uv, dpdu, dpdv)
  333. Geom *prim;
  334. Vector *pos, *norm, *dpdu, *dpdv;
  335. Vec2d *uv;
  336. {
  337.     /*
  338.      * Call appropriate inverse mapping routine
  339.      */
  340.     if (prim->methods->uv == NULL) {
  341.         uv->u = uv->v = 0.;
  342.         if (dpdu) {
  343.             dpdu->y = dpdu->z = 0.;
  344.             dpdu->x = 1.;
  345.         }
  346.         if (dpdv) {
  347.             dpdv->x = dpdv->z = 0.;
  348.             dpdv->y = 1.;
  349.         }    
  350.     } else
  351.         (*prim->methods->uv)(prim->obj,pos,norm,uv,dpdu,dpdv);
  352. }
  353.  
  354. int
  355. PrimNormal(prim, pos, norm, gnorm)
  356. Geom *prim;
  357. Vector *pos, *norm, *gnorm;
  358. {
  359.     /*
  360.      * Call appropriate normal routine
  361.      */
  362.     return (*prim->methods->normal) (prim->obj, pos, norm, gnorm);
  363. }
  364.  
  365. int
  366. PrimEnter(obj, ray, mind, hitd)
  367. Geom *obj;
  368. Ray *ray;
  369. Float mind, hitd;
  370. {
  371.     /*
  372.      * Call appropriate enter/leave routine
  373.      */
  374.     if (obj->methods->enter == NULL) {
  375.         Vector pos, nrm, gnrm;
  376.         /*
  377.          * Sleazy method:  Use hit point, find normal 
  378.          * and take dot prod with ray 
  379.          */
  380.         VecAddScaled(ray->pos, hitd, ray->dir, &pos);
  381.         PrimNormal(obj, &pos, &nrm, &gnrm);
  382.  
  383.         return dotp(&ray->dir, &gnrm) < 0.0;
  384.     }
  385.     else
  386.         return (*obj->methods->enter) (obj->obj, ray, mind, hitd);
  387. }
  388.  
  389. /*
  390.  * Walk through a linked-list of objects.  If the object is unbounded,
  391.  * unlink it it from the list and add it to the 'unbounded' list.
  392.  * If the object is bounded, enlarge the given bounding box if
  393.  * necessary.  Return pointer to unbounded list.
  394.  */
  395. Geom *
  396. GeomComputeAggregateBounds(bounded, unbounded, bounds)
  397. Geom **bounded, *unbounded;
  398. Float bounds[2][3];
  399. {
  400.     Geom *ltmp, *prev, *nextobj;
  401.  
  402.     BoundsInit(bounds);
  403.  
  404.     prev = (Geom *)0;
  405.  
  406.     for (ltmp = *bounded; ltmp; ltmp = nextobj) {
  407.         nextobj = ltmp->next;
  408.         GeomComputeBounds(ltmp);
  409.         if (UNBOUNDED(ltmp)) {
  410.             /*
  411.              * Geom is unbounded -- unlink it...
  412.              */
  413.             if (prev)
  414.                 prev->next = ltmp->next;
  415.             else
  416.                 *bounded = ltmp->next;
  417.             /*
  418.              * And add it to unbounded object list.
  419.              */
  420.             ltmp->next = unbounded;
  421.             unbounded = ltmp;
  422.         } else {
  423.             /*
  424.              * Geom is bounded.
  425.              */
  426.             BoundsEnlarge(bounds, ltmp->bounds);
  427.             prev = ltmp;
  428.         }
  429.     }
  430.     return unbounded;
  431. }
  432.  
  433. /*
  434.  * Find 'highest' animated object on the hitlist.
  435.  */
  436. int
  437. FirstAnimatedGeom(hitlist)
  438. HitList *hitlist;
  439. {
  440.     int i;
  441.  
  442.     for (i = hitlist->nodes -1; i; i--)
  443.         /*
  444.          * If object itself is animated, have
  445.          * to check other flag, too...
  446.          */
  447.         if (hitlist->data[i].obj->animtrans)
  448.             return i;
  449.     return 0;
  450. }
  451.